package ru.kurganec.ifmo.netland.core;

import org.apache.log4j.Logger;
import ru.kurganec.ifmo.netland.event.*;
import ru.kurganec.ifmo.netland.event.chat.*;
import ru.kurganec.ifmo.netland.util.ChatChannel;
import ru.kurganec.ifmo.netland.util.ChatUser;
import ru.kurganec.ifmo.netland.util.HardwareInfo;

import java.awt.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.Vector;

/**
 * Created by IntelliJ IDEA.
 * User: oo
 * Date: 12.07.11
 * Time: 23:02
 */
public class Netland implements NetlandCommandListener, ChatEventProducer {
    // ===========================================================
    // Constants
    // ===========================================================

    // ===========================================================
    // Fields
    // ===========================================================

    private static Logger logger = Logger.getLogger(NetlandReceiver.class);
    private Vector<ChatEventListener> chatListeners = new Vector<ChatEventListener>();
    private HashMap<String, Command> bigSwitchMap = new HashMap<String, Command>();

    private NetlandReceiver receiver;
    private boolean  accepted = false;

    // ===========================================================
    // Constructors
    // ===========================================================
    public Netland(final NetlandReceiver  receiver) {
            this.receiver = receiver;
        initSwitchMap();

        }




    // ===========================================================
    // Getter & Setter
    // ===========================================================


    public void setReceiver(NetlandReceiver receiver) {
        this.receiver = receiver;
    }

    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================
    @Override
    public void commandReceived(NetlandCommand command) {
        //logger.info(command.getMessage().replace('\r', '\n'));
        String msg = command.getMessage();
        int firstT = msg.indexOf('\t');
        Command cmd;
        if (firstT == -1) {
            cmd = bigSwitchMap.get(msg);
        } else {
            String name = msg.substring(0, firstT);
            cmd = bigSwitchMap.get(name);
        }
        if (cmd != null) {

            switch (cmd) {
                case cip: {
                    fireIpPerformed(msg);
                    break;
                }
                case center: {
                    fireEnterPerformed(msg);
                    break;
                }
                case cleave: {
                    fireLeavePerformed(msg);
                    break;
                }
                case cmain: {
                    fireMainPerformed(msg);
                    break;
                }
                case cuserlist: {
                    fireUserListPerformed(msg);
                    break;
                }
                case cprivate: {
                    firePrivateMessagePerformed(msg);
                    break;
                }
                case cinfoGet: {
                    logger.error("cinfoGet: " + msg.replace('\r', '\t'));
                    //TODO: send to chatlistener or not?
                    break;
                }
                case  cchannels: {
                    fireChannelsPerformed(msg);
                    break;

                }

                case dadmin: {
                    logger.info("dadmin: " + msg.replace('\r','\t'));
                    break;
                }

                case dskins: {
                    logger.info("dskins: " + msg.replace('\r','\t'));
                    break;

                }
                case dchannels: {
                    logger.info("dchannels: " + msg.replace('\r','\t'));
                    break;
                }


            }
        } else { //SingleChar command   or unsopported
            logger.debug("SCCommand: " + msg);
            if (msg.startsWith("R") ) {
                sendClientVerificationInfo();
            }
            else if (msg.startsWith("b")) {
                if (msg.contains("принят")) {
                    accepted = true;
                    logger.info("Client Accepted");
                }


            } else if (msg.startsWith("l")) {

            } else if (msg.startsWith("F")) {

            } else if (msg.startsWith("a")) {

            } else {
                logger.error("Unsopported: "+ msg.replace('\r', '\t'));
            }

        }


    }

    @Override
    public void receiverConnected(NetlandCommand command) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    receiver.sendCommand("cuserlist");
                    try {
                        Thread.sleep(60000);
                    } catch (InterruptedException e) {
                        continue;
                    }

                }
            }
        }).start();
        receiver.sendCommand("cnik\tNetland2.0");
    }

    @Override
    public void addChatEventListener(ChatEventListener listener) {
        chatListeners.add(listener);
    }

    @Override
    public ChatEventListener[] getChatEventListeners() {
        return chatListeners.toArray(new ChatEventListener[chatListeners.size()]);
    }

    @Override
    public void removeChatEventListener(NetlandCommandListener listener) {
        chatListeners.remove(listener);
    }

    @Override
    public void fireEnterPerformed(String message) {
        //parse here
        String [] param =  splitParams(message);//message.split("\t");
        if (param.length == 7) {
            logger.info("center: " + trim(message));
            EnterEvent enterEvent = new EnterEvent(this, message,
                    param[1],param[2],param[3],param[4],param[5], param[6].replace("\n", ""));
            for (ChatEventListener listener : chatListeners) {
                listener.enterPerformed(enterEvent);
            }
        } else {
            logger.error("wrong center: " + trim(message));
        }
    }

    @Override
    public void fireMainPerformed(String message) {
        String [] param = splitParams(message);//message.split("\t");

        if (param.length == 4) {
            logger.info("cmain: " +trim(message));
            MainEvent event = new MainEvent(this, message, param[1], param[2], param[3], param[4].replace("\n", ""));
            for (ChatEventListener listener : chatListeners) {
                listener.mainPerformed(event);
            }
        } else {
            logger.info("Wrong cmain: " + trim(message));
        }


    }

    @Override
    public void fireLeavePerformed(String message) {
        String [] params = splitParams(message);//message.split("\t");
        if (params.length == 7 ) { //TODO: waht does another cleave mean?
            logger.info("cleave: " + trim(message));
            LeaveEvent event = new LeaveEvent(this, message,
                    params[1], params[2], params[3], params[4], params[5], params[6].replace("\n", ""));
            for (ChatEventListener listener: chatListeners) {
                listener.leavePerformed(event);
            }
        } else {
            logger.error("wrong leave: " + trim(message));
        }
    }

    @Override
    public void fireIpPerformed(String message) {


        String [] params = splitParams(message);//message.split("\t");
        if (params.length == 3) {
            logger.info("cip: " + trim(message)); //if debug?

            IpEvent event = new IpEvent(this, message, params[1], params[2]);
            for (ChatEventListener listener: chatListeners) {
                listener.ipPerformed(event);
            }
        } else {
            logger.error("Wrong cip: " + trim(message));
        }

    }

    @Override
    public void fireUserListPerformed(String message) {
        logger.info("cuserList: " + trim(message));
        //TODO Check parametres
        message = message.replace("\n", "");
        message = message.replaceAll("cuserlist.Netland.", "");
        String [] users = splitLists(message);//message.replace("\n", "").split("\r");
        ArrayList<ChatUser> userList = new ArrayList<ChatUser>();
        for (int i =0; i < users.length; ++i) {
            String [] param = users[i].split("\t", 4);
            //TODO Check parametres
            userList.add(new ChatUser(param[0], param[1], param[2], param[3]));
        }
        UserListEvent event = new UserListEvent(this, message, userList);
        for (ChatEventListener listener : chatListeners) {
            listener.userListPerformed(event);
        }

    }

    @Override
    public void fireChannelsPerformed(String message) {
        //TODO: check params :(
        logger.info("cchannels: " + trim(message));
        message = message.replace("\n", "");
        message = message.replaceAll("cchannels.", "");
        String [] channels = splitLists(message);

        ArrayList<ChatChannel> channelsList = new ArrayList<ChatChannel>(4);
        for (String channel: channels) {
            String [] params = splitParams(channel);
            channelsList.add(new ChatChannel(params[0], params[1]));
        }

        for (ChatEventListener listener: chatListeners) {
            listener.channelsPerformed(new ChannelEvent(this, message, channelsList));
        }


    }

    @Override
    public void firePrivateMessagePerformed(String message) {

        String [] param = message.split("\t");
        if (param.length == 7) {
            logger.info("cprivate: " + trim(message));
            PrivateMessageEvent event = new PrivateMessageEvent(this, message,
                    param[1], param[2], param[3], param[4], param[5], param[6]);
            for (ChatEventListener listener: chatListeners) {
                listener.privateMessagePerformed(event);
            }
        } else {
            logger.error("Wrong cprivate: " + trim(message));
        }
    }

    // ===========================================================
    // Methods
    // ===========================================================
    public static void main(String[] args) {
        NetlandReceiver receiver = new NetlandReceiver();
        Netland client = new Netland(receiver);
        receiver.addCommandListener(client);
        Thread receiverThread;
        try {
            receiverThread = receiver.connect();
        } catch (IOException e) {
            logger.error(e.getMessage());
            System.exit(100);
        }
    }

    void sendClientVerificationInfo() {
        StringBuilder verInfo = new StringBuilder();
        verInfo.append("v8.6\t");
        verInfo.append("GPOLFAABINENJOFNIEEIIKFGIKECIAFH\t");
        verInfo.append(HardwareInfo.getMotherboardSN()); verInfo.append("\t");




        Properties sysp = System.getProperties();
        verInfo.append(sysp.get("os.name"));
        verInfo.append(' ');
        verInfo.append(sysp.get("os.version"));
        verInfo.append('\t');
        try {
            verInfo.append(InetAddress.getLocalHost().getHostName());
        } catch (UnknownHostException e) {
            verInfo.append("lcoalhost:)\n");
        }
        receiver.sendCommand(verInfo.toString());
//        receiver.sendCommand("v8.6\tGPOLFAABINENJOFNIEEIIKFGIKECIAFH\t0F41-BFEB-FBFF-441D 10/06/03 3C90-DA6C v.6.0\t"
//        +"(6001) win32onNT Windows Vista SP1\t33-vadikus");
        //receiver.sendCommand("wtemp");


    }

    private enum Command {
        cip,
        center,//++
        cleave,//++
        cmain,//++
        cuserlist,
        cprivate,
        //cnik,
        cinfoGet,
        cchannels,
        //Bulletin board
        dadmin,
        dskins ,
        dchannels,
    }

    private void initSwitchMap() {
        //Chat commands
        //starts with 'c'
        bigSwitchMap.put("center", Command.center);
        bigSwitchMap.put("cip", Command.cip);
        bigSwitchMap.put("cprivate", Command.cprivate);
        //bigSwitchMap.put("cnik", Command.cnik);
        bigSwitchMap.put("cmain", Command.cmain);
        bigSwitchMap.put("cleave", Command.cleave);
        bigSwitchMap.put("cinfoGet", Command.cinfoGet);
        bigSwitchMap.put("cchannels", Command.cchannels);
        bigSwitchMap.put("cuserlist", Command.cuserlist);
        //BB commands starts with d
        bigSwitchMap.put("dadmin\n", Command.dadmin);
        bigSwitchMap.put("dskins", Command.dskins) ;
        bigSwitchMap.put("dchannels", Command.dchannels);
    }
    private String trim (String str) {
        return  str.replace('\r','\t');
    }
    private String [] splitLists(String str) {
        return str.split("\r");
    }

    private String [] splitParams(String str) {
        return str.split("\t");
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================



}
